#include <stdio.h>
#include <string.h>
#include "kfifo.h"
#include "main.h"	
#include "earbud_cmd.h"
#include "msg.h"
#include "hall.h"
#include "sw_timer.h"
#include "usart.h"
#include "sy8801.h"
#include "app_user.h"


#if (SUPPORT_UART_COMM)

//UART3  EAR_L	0x11
//UART2  EAR_R	0x22


uint8_t earbud_l_comm_timeout_tiemr = 0xff;
uint8_t earbud_l_comm_timeout_count = 0;

uint8_t earbud_r_comm_timeout_tiemr = 0xff;
uint8_t earbud_r_comm_timeout_count = 0;

uint8_t earbud_l_comm_tiemr = 0xff;
uint8_t earbud_r_comm_tiemr = 0xff;

uint8_t earbud_l_comm_delay_tiemr = 0xff;
uint8_t earbud_r_comm_delay_tiemr = 0xff;
uint8_t earbud_comm_delay_role = 0;

uint8_t earbud_action = 0;

EAR_STATE_INFO ear_info = {0};




//////////////////////////////////////////////命令队列
EAR_CMD_INFO ear_cmd[2] = {0};
uint8_t earbud_comm_cmd[2] = {0};
uint8_t earbud_comm_cmd_count[2] = {0};


void earbud_cmd_init(void)
{
    
}

void earbud_cmd_push(uint8_t role, uint8_t id)
{
    uint8_t index;
    
    if(ear_cmd[role].size >= EAR_CMD_COUNT)
        return;
    
    index = ear_cmd[role].tail;
    ear_cmd[role].tail++;
    if(ear_cmd[role].tail >= EAR_CMD_COUNT)
        ear_cmd[role].tail = 0;
    
    ear_cmd[role].cmd[index] = id;
    //ear_cmd[role].timeout_count = 20;
    ear_cmd[role].size++;
}

uint8_t earbud_cmd_pop(uint8_t role, uint8_t *id)
{
    if(ear_cmd[role].size == 0)
    {
        *id = 0;
        return 0;
    }
    
    ear_cmd[role].size--;
    *id = ear_cmd[role].cmd[ear_cmd[role].head];
        
    ear_cmd[role].head++;
    if(ear_cmd[role].head >= EAR_CMD_COUNT)
        ear_cmd[role].head = 0;

    return 1;
}

void earbud_cmd_clear(uint8_t role)
{
    ear_cmd[role].size = 0;
    ear_cmd[role].head = 0;
    ear_cmd[role].tail = 0;
}

void earbud_cmd_next(uint8_t role)
{
    if(ear_cmd[role].size == 0)
    {
        earbud_comm_cmd[role] = 0x00;
        return;
    }
    
    earbud_cmd_pop(role, &earbud_comm_cmd[role]);
    earbud_comm_cmd_count[role] = 20;
}
////////////////////////////////////////////////////////////////////


static uint8_t get_crc8(uint8_t *buff, uint8_t length)
{
    uint8_t i;
    uint8_t crc = 0; // initial value
    while (length--)
    {
        crc ^= *buff++; // crc ^= *buff; buff++;
        for (i = 0; i < 8; i++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8C; // 0x8C = reverse 0x31
            else
                crc >>= 1;
        }
    }
    return crc;
}

void earbud_send_rsp(uint8_t ear_type, uint8_t op,  uint8_t *buf, uint8_t len)
{
	//uint8_t battery[] = {0x55,0xaa,0x08,0x22,0x01,0x01,0x16};
    uint8_t buffer[16], i;

    buffer[0] = 0x55;
    buffer[1] = 0xaa;
    buffer[2] = op;
    buffer[3] = (ear_type==EAR_L) ? EAR_L_ROLE_CMD_FLAG : EAR_R_ROLE_CMD_FLAG;
	
    buffer[4] = len;
	if(len > 0)
	{
		for(i=0; i<len; i++)
			buffer[5+i] = buf[i];
	}
	
    buffer[5+len] = get_crc8(buffer, 5+len);

    earbud_comm_send_data(buffer, 6+len);
}

void earbud_comm_send_data(uint8_t *data, uint8_t len)
{
	if(data[3] == EAR_L_ROLE_CMD_FLAG)
		uart3_send(data, len);		//L
	else
		uart2_send(data, len);		//R
}


void earbud_comm_send_cmd(uint8_t role, uint8_t cmd)
{
    //BOX_LOG("cmd push: %d, 0x%x\n", role, cmd);
    earbud_cmd_push(role, cmd);
}

uint8_t earbud_data_decode(uint8_t ear_role, uint8_t* buf, uint8_t len)
{
	uint8_t crc;
	
	if((ear_role == EAR_L && buf[3] != EAR_L_ROLE_CMD_FLAG)
		|| (ear_role == EAR_R && buf[3] != EAR_R_ROLE_CMD_FLAG))
		return 1;
	
	if(buf[0] != 0x55 || buf[1] != 0xAA)
		return 2;
	
	if((buf[4]+6) != len)
		return 3;
	
	crc = get_crc8(buf, len-1);
	if(crc != buf[len-1])
		return 4;
	
	earbud_cmd_decode(ear_role, buf, len);
	return 0;
}

uint8_t earbud_cmd_decode(uint8_t role, uint8_t* buf, uint8_t len)
{
	//0x55,0xaa,0x08,0x22,0x01,0x01,0x16
	uint8_t cmd = buf[2];
	uint8_t *param, param_len;
	
	param = buf + 5;
	param_len = len - 6;

    if(role == EAR_L)
    {
        earbud_l_comm_timeout_count = 0;
        earbud_l_comm_timeout_timer_stop();
        if(ear_info.box_status[EAR_L] != EAR_IN_BOX)
    	{
    	    BOX_LOG("L comm ok\n");
    		ear_info.box_status[EAR_L] = EAR_IN_BOX;
#if (SUPPORT_UART_TA012_CMD)
            earbud_comm_send_cmd(EAR_L, CMD_GET_MAC);
#endif
    	}
    }
    else
    {
        earbud_r_comm_timeout_count = 0;
        earbud_r_comm_timeout_timer_stop();
        if(ear_info.box_status[EAR_R] != EAR_IN_BOX)
		{
		    BOX_LOG("R comm ok\n");
			ear_info.box_status[EAR_R] = EAR_IN_BOX;
#if (SUPPORT_UART_TA012_CMD)
            earbud_comm_send_cmd(EAR_R, CMD_GET_MAC);
#endif
		}
    }
    
	//BOX_LOG("cmd: 0x%x\n", cmd);
	switch(cmd)
	{
	    case CMD_OPENCASE:
            if(role == EAR_L)
                BOX_LOG("L open case\n");
            else
                BOX_LOG("R open case\n");
            break;
            
	    case CMD_CLOSECASE:
            if(role == EAR_L)
                BOX_LOG("L close case\n");
            else
                BOX_LOG("R close case\n");
            app_close_box_callback(role);
            break;
            
        case CMD_POWEROFF:
            if(role == EAR_L)
                BOX_LOG("L power off\n");
            else
                BOX_LOG("R power off\n");
            break;

        case CMD_FACTORY_RESET_KEEP_WWS:
            if(role == EAR_L)
                BOX_LOG("L factory reset ok\n");
            else
                BOX_LOG("R factory reset ok\n");
            break;
            
		case CMD_BATTERY:
			{
				uint8_t bat = (*param)>>4;
				uint8_t state = (*param)&0x0F;
                    
				if(role == EAR_L)
				{
				    if(ear_info.bat[EAR_L] != bat)
                    {
                        BOX_LOG("L bat, old:%d, new:%d\n", ear_info.bat[EAR_L], bat);
                        ear_info.bat[EAR_L] = bat;
                    }
                    if(ear_info.bt_status[EAR_L] != state)
                    {
                        BOX_LOG("L status, old:0x%x, new:0x%x\n", ear_info.bt_status[EAR_L], state);
					    ear_info.bt_status[EAR_L] = state;
                    }
				}
				else
				{
					if(ear_info.bat[EAR_R] != bat)
                    {
                        BOX_LOG("R bat, old:%d, new:%d\n", ear_info.bat[EAR_R], bat);
                        ear_info.bat[EAR_R] = bat;
                    }
                    if(ear_info.bt_status[EAR_R] != state)
                    {
                        BOX_LOG("R status, old:0x%x, new:0x%x\n", ear_info.bt_status[EAR_R], state);
					    ear_info.bt_status[EAR_R] = state;
                    }
				}
#if (SUPPORT_UART_TA006_CMD)
                if(role == EAR_L)
				{
				    if(ear_info.printf_addr_flag[EAR_L] == 0)
                    {            
                        ear_info.printf_addr_flag[EAR_L] = 1;
                        memcpy(ear_info.load_addr[EAR_L], param+1, 6);
                        memcpy(ear_info.peer_addr[EAR_L], param+7, 6);
                        
    				    BOX_LOG("L load addr: ");
    				    printf_array(param+1, 6);
                        BOX_LOG("L peer addr: ");
                        printf_array(param+7, 6);
#if (SUPPORT_UART_AUTO_TWS_PAIR)
                        earbud_auto_tws_pair_check();
#endif
                    }
                }
                else
                {
                    if(ear_info.printf_addr_flag[EAR_R] == 0)
                    {            
                        ear_info.printf_addr_flag[EAR_R] = 1;
                        memcpy(ear_info.load_addr[EAR_R], param+1, 6);
                        memcpy(ear_info.peer_addr[EAR_R], param+7, 6);
                        
                        BOX_LOG("R load addr: ");
    				    printf_array(param+1, 6);
                        BOX_LOG("R peer addr: ");
                        printf_array(param+7, 6);
#if (SUPPORT_UART_AUTO_TWS_PAIR)
                        earbud_auto_tws_pair_check();
#endif
                    }
                }
#endif
			}
			break;
		
		case CMD_PAIRING:
			if(role == EAR_L)
				BOX_LOG("L enter pair ok\n");
			else
				BOX_LOG("R enter pair ok\n");
			break;
		
		case CMD_GET_MAC:
			{
				if(role == EAR_L)
				{
					memcpy(ear_info.load_addr[EAR_L], param, param_len);
					BOX_LOG("L get addr: ");
					printf_array(param, param_len);
                    //earbud_comm_send_cmd(EAR_L, CMD_NULL);
				}
				else
				{
					memcpy(ear_info.load_addr[EAR_R], param, param_len);
					BOX_LOG("R get addr: ");
					printf_array(param, param_len);
                    //earbud_comm_send_cmd(EAR_R, CMD_NULL);
				}
			}
			break;
		
		case CMD_SET_MAC:
			{
				if(role == EAR_L)
                {            
					BOX_LOG("L set addr success\n");
                    earbud_comm_send_cmd(EAR_L, CMD_FACTORY_RESET_KEEP_WWS);
                }
				else
                {            
					BOX_LOG("R set addr success\n");
                    earbud_comm_send_cmd(EAR_R, CMD_FACTORY_RESET_KEEP_WWS);
                }
			}
			break;
		default:
			BOX_LOG("unknown cmd: %d, 0x%x\n", role, cmd);
			break;
	}

    earbud_cmd_next(role);
    return 0;
}

void printf_ear_cmd_array(uint8_t* buf, uint8_t len)
{
	uint8_t i;
	
	if(buf[3] == EAR_L_ROLE_CMD_FLAG)
		BOX_LOG("L rx:%d, ", len);
	else
		BOX_LOG("R rx:%d, ", len);
	
	for(i=0; i<len; i++)
	{
		BOX_LOG("%02X ", buf[i]);
	}
	BOX_LOG("\n");	
}

void printf_array(uint8_t* buf, uint8_t len)
{
	uint8_t i;
	
	for(i=0; i<len; i++)
	{
		BOX_LOG("%02X ", buf[i]);
	}
	BOX_LOG("\n");	
}

void earbud_cmd_handle(uint8_t msg_id, uint8_t* buf, uint8_t len)
{
	uint8_t ret;
	
	//printf_ear_cmd_array(buf, len);
	
	switch(msg_id)
	{
		case MSG_EAR_L_RX:
			ret = earbud_data_decode(EAR_L, buf, len);
			if(ret != 0)
				BOX_LOG("L cmd err:%d, len:%d\n", ret, len);
			break;
		
		case MSG_EAR_R_RX:
			ret = earbud_data_decode(EAR_R, buf, len);
			if(ret != 0)
				BOX_LOG("R cmd err:%d, len:%d\n", ret, len);
			break;
	}
}

uint8_t addr_is_empty(uint8_t *addr)
{	
	if(addr[0] == 0x00 && addr[1] == 0x00 && addr[2] == 0x00
         && addr[3] == 0x00 && addr[4] == 0x00 && addr[5] == 0x00)
		return 1;
    
    if(addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff
         && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff)
		return 1;
    
	return 0;
}


void earbud_enter_pair(void)
{
    earbud_comm_send_cmd(EAR_L, CMD_PAIRING);
    earbud_comm_send_cmd(EAR_R, CMD_PAIRING);
}

void earbud_factory_reset(void)
{
	if(addr_is_empty(ear_info.load_addr[EAR_L]) 
		|| addr_is_empty(ear_info.load_addr[EAR_R]))
	{
		return;
	}

    earbud_comm_send_cmd(EAR_L, CMD_SET_MAC);
    earbud_comm_send_cmd(EAR_R, CMD_SET_MAC);
}

#if (SUPPORT_UART_AUTO_TWS_PAIR)
void earbud_auto_tws_pair_check(void)
{
    if(ear_info.printf_addr_flag[EAR_L] && ear_info.printf_addr_flag[EAR_R])
    {
        if(memcmp(ear_info.load_addr[EAR_L], ear_info.peer_addr[EAR_R], 6) 
            || memcmp(ear_info.load_addr[EAR_R], ear_info.peer_addr[EAR_L], 6))
        {
            earbud_factory_reset();
        }
    }
}
#endif

uint8_t earbud_check_is_in_box(uint8_t role)
{
    uint8_t reg_load;
    
    if(role == EAR_L)
    {
        uart3_deinit();
        HAL_Delay(80);
        reg_load = sy880x_read_reg(ADDR_sy8801_ST_LOAD);
        //BOX_LOG("L reg_load: %x\n", reg_load);
        if(reg_load & 0x04)
        {
            MX_USART3_UART_Init();
		    uart3_rx_enable();
            return 1;
        }
        else
            return 0;
    }
    else
    {
        uart2_deinit();
        HAL_Delay(80);
        reg_load = sy880x_read_reg(ADDR_sy8801_ST_LOAD);
        //BOX_LOG("R reg_load: %x\n", reg_load);
        if(reg_load & 0x08)
        {
            MX_USART2_UART_Init();
		    uart2_rx_enable();
            return 1;
        }
        else
            return 0;
    }
}

void earbud_comm_timeout_handle(uint8_t role)
{
    uint8_t state = role;
    
    ear_info.box_status[role] = EAR_OUT_BOX;
    if(role == EAR_L)
    {
        BOX_LOG("L comm timeout\n");
        earbud_l_comm_timeout_timer_stop();
        earbud_l_comm_timer_stop();
    }
    else
    {
        BOX_LOG("R comm timeout\n");
        earbud_r_comm_timeout_timer_stop();
        earbud_r_comm_timer_stop();
    }
    app_msg_send_with_param(MSG_EAR_OUT_BOX, &state, 1);
}

void earbud_l_comm_timeout_callback(void)
{
    earbud_l_comm_timeout_tiemr = 0xff;
    
    if(earbud_check_is_in_box(EAR_L))
    {
        earbud_l_comm_timeout_count++;
        if(earbud_l_comm_timeout_count > EAR_COMM_TIMEOUT_COUNT)
        {
            BOX_LOG("L comm timeout, fail\n");
            earbud_l_comm_timeout_count = 0;
            earbud_comm_timeout_handle(EAR_L);
        }
    }
    else
    {
        earbud_comm_timeout_handle(EAR_L);
    }
}
void earbud_l_comm_timeout_timer_stop(void)
{
    if(earbud_l_comm_timeout_tiemr != 0xff)
	{
		sw_timer_stop(earbud_l_comm_timeout_tiemr);
		earbud_l_comm_timeout_tiemr = 0xff;
	}
}
void earbud_l_comm_timeout_timer_start(void)
{
    earbud_l_comm_timeout_timer_stop();
	earbud_l_comm_timeout_tiemr = sw_timer_start(EAR_COMM_TIMEOUT_TIME, 0, earbud_l_comm_timeout_callback);
}


void earbud_r_comm_timeout_callback(void)
{
    earbud_r_comm_timeout_tiemr = 0xff;
    
    if(earbud_check_is_in_box(EAR_R))
    {
        earbud_r_comm_timeout_count++;
        if(earbud_r_comm_timeout_count > EAR_COMM_TIMEOUT_COUNT)
        {
            BOX_LOG("R comm timeout, fail\n");
            earbud_r_comm_timeout_count = 0;
            earbud_comm_timeout_handle(EAR_R);
        }
    }
    else
    {
        earbud_comm_timeout_handle(EAR_R);
    }
}
void earbud_r_comm_timeout_timer_stop(void)
{
    if(earbud_r_comm_timeout_tiemr != 0xff)
	{
		sw_timer_stop(earbud_r_comm_timeout_tiemr);
		earbud_r_comm_timeout_tiemr = 0xff;
	}
}
void earbud_r_comm_timeout_timer_start(void)
{
    earbud_r_comm_timeout_timer_stop();
    earbud_r_comm_timeout_tiemr = sw_timer_start(EAR_COMM_TIMEOUT_TIME, 0, earbud_r_comm_timeout_callback);
}

void earbud_l_comm_callback(void)
{
    if((ear_info.box_status[EAR_L] != EAR_IN_BOX) || (earbud_comm_cmd[EAR_L] == 0))
    {
        uint8_t box_bat = app_bat_get_level()/10;
        earbud_send_rsp(EAR_L, CMD_BATTERY, &box_bat, 1);
    }
    else
    {
        if(earbud_comm_cmd[EAR_L] == CMD_SET_MAC)
            earbud_send_rsp(EAR_L, CMD_SET_MAC, ear_info.load_addr[EAR_R], 6);
        else
            earbud_send_rsp(EAR_L, earbud_comm_cmd[EAR_L], NULL, 0);
    }
    earbud_l_comm_timeout_timer_start();
}
void earbud_l_comm_timer_stop(void)
{
    if(earbud_l_comm_tiemr != 0xff)
	{
		sw_timer_stop(earbud_l_comm_tiemr);
		earbud_l_comm_tiemr = 0xff;
	}
}
void earbud_l_comm_timer_start(void)
{
    earbud_l_comm_timer_stop();
	earbud_l_comm_tiemr = sw_timer_start(EAR_COMM_INTERVAL_TIME, 1, earbud_l_comm_callback);
    earbud_l_comm_timeout_count = 0;
}

void earbud_r_comm_callback(void)
{
    if((ear_info.box_status[EAR_R] != EAR_IN_BOX) || (earbud_comm_cmd[EAR_R] == 0))
    {
        uint8_t box_bat = 1;
        earbud_send_rsp(EAR_R, CMD_BATTERY, &box_bat, 1);
    }
    else
    {
        if(earbud_comm_cmd[EAR_R] == CMD_SET_MAC)
            earbud_send_rsp(EAR_R, CMD_SET_MAC, ear_info.load_addr[EAR_L], 6);
        else
            earbud_send_rsp(EAR_R, earbud_comm_cmd[EAR_R], NULL, 0);
    }

    earbud_r_comm_timeout_timer_start();
}
void earbud_r_comm_timer_stop(void)
{
    if(earbud_r_comm_tiemr != 0xff)
	{
		sw_timer_stop(earbud_r_comm_tiemr);
		earbud_r_comm_tiemr = 0xff;
	}
}
void earbud_r_comm_timer_start(void)
{
    earbud_r_comm_timer_stop();
	earbud_r_comm_tiemr = sw_timer_start(EAR_COMM_INTERVAL_TIME, 1, earbud_r_comm_callback);
    earbud_r_comm_timeout_count = 0;
}

uint8_t earbud_comm_is_activity(uint8_t role)
{
    if(role == EAR_L)
    {
        if(earbud_l_comm_tiemr != 0xff || earbud_l_comm_delay_tiemr != 0xff)
            return 1;
    }
    else
    {
        if(earbud_r_comm_tiemr != 0xff || earbud_r_comm_delay_tiemr != 0xff)
            return 1;
    }
    return 0;
}

void earbud_delay_start_comm_callback(void)
{
    BOX_LOG("delay comm callback: %x\n", earbud_comm_delay_role);
    if(earbud_comm_delay_role & (1<<EAR_L))
    {
        earbud_l_comm_delay_tiemr = 0xff;
        earbud_comm_delay_role &= ~(1<<EAR_L);
        sy8801_ear_5v_output_disable(1<<EAR_L);
        earbud_start_comm(EAR_L);
    }
    
    if(earbud_comm_delay_role & (1<<EAR_R))
    {
        earbud_r_comm_delay_tiemr = 0xff;
        earbud_comm_delay_role &= ~(1<<EAR_R);
        sy8801_ear_5v_output_disable(1<<EAR_R);
        earbud_start_comm(EAR_R);
    }
}

void earbud_comm_delay_timer_stop(uint8_t role)
{
    if(role == EAR_L)
    {
        if(earbud_l_comm_delay_tiemr != 0xff)
            earbud_l_comm_delay_tiemr = sw_timer_stop(earbud_l_comm_delay_tiemr);
    }
    else
    {
        if(earbud_r_comm_delay_tiemr != 0xff)
            earbud_r_comm_delay_tiemr = sw_timer_stop(earbud_r_comm_delay_tiemr);
    }
}


void earbud_delay_start_comm(uint8_t role)
{
    BOX_LOG("delay start comm: %d\n", role);
    
    if(role == EAR_L)
    {
        if(earbud_l_comm_delay_tiemr != 0xff)
            return;
        sy8801_ear_5v_output_enable(1<<role);
        earbud_comm_delay_role |= 1<<role;
        earbud_l_comm_delay_tiemr = sw_timer_start(EAR_COMM_ACTIVATE_TIME, 0, earbud_delay_start_comm_callback);
    }
    else
    {
        if(earbud_r_comm_delay_tiemr != 0xff)
            return;
        sy8801_ear_5v_output_enable(1<<role);
        earbud_comm_delay_role |= 1<<role;
        earbud_r_comm_delay_tiemr = sw_timer_start(EAR_COMM_ACTIVATE_TIME, 0, earbud_delay_start_comm_callback);
    }
}

void earbud_start_comm(uint8_t role)
{
	if(role == EAR_L)
	{
		BOX_LOG("L start comm\n");
		MX_USART3_UART_Init();
		uart3_rx_enable();
		earbud_l_comm_timer_start();
        earbud_l_comm_timeout_timer_start();
	}
	else
	{
		BOX_LOG("R start comm\n");
		MX_USART2_UART_Init();
		uart2_rx_enable();
		earbud_r_comm_timer_start();
        earbud_r_comm_timeout_timer_start();
	}
}

void earbud_stop_comm(uint8_t role)
{
	if(role == EAR_L)
	{
	    BOX_LOG("L stop comm\n");
        earbud_comm_delay_timer_stop(EAR_L);
	    earbud_l_comm_timer_stop();
        earbud_l_comm_timeout_timer_stop();
		uart3_deinit();
        earbud_state_clear(EAR_L);
	}
	else
	{
	    BOX_LOG("R stop comm\n");
        earbud_comm_delay_timer_stop(EAR_R);
	    earbud_r_comm_timer_stop();
        earbud_r_comm_timeout_timer_stop();
		uart2_deinit();
        earbud_state_clear(EAR_R);
	}
}

void earbud_state_clear(uint8_t role)
{
    ear_info.box_status[role] = 0xff;
    ear_info.bt_status[role] = 0xff;

    ear_info.printf_addr_flag[role] = 0;
}

void earbud_comm_init(void)
{
    earbud_cmd_init();
        
    earbud_state_clear(EAR_L);
    earbud_state_clear(EAR_R);
    
    earbud_stop_comm(EAR_L);
    earbud_stop_comm(EAR_R);
}

void earbud_comm_deinit(void)
{
    
}

#endif

